package com.vladimirjosu.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;

public class Util {
	public static void log(String string) {
		System.out.print(string);
	}

	public static String getResourcePath(String fileName) {
		String path = getUserDirectory() + "/res/" + fileName;
		return path;
	}

	public static String getInputPath(String fileName) {
		String path = getUserDirectory() + "/input/" + fileName;
		return path;
	}

	public static String getUserDirectory() {
		String path = System.getProperty("user.dir");
		return path;
	}

	public static String getUserDirectory(String dir) {
		return getUserDirectory() + "/" + dir;
	}

	public static InputStream getSourceStream(String file) {
		FileInputStream stream = null;
		try {
			stream = new FileInputStream(getResourcePath(file));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		// Util.log("Input stream = " + stream);
		return stream;
	}

	public static InputStream getInputStream(String file) {
		FileInputStream stream = null;
		try {
			stream = new FileInputStream(getInputPath(file));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		// Util.log("Input stream = " + stream);
		return stream;
	}

	public static boolean replaceInFile(String filePath, String replaceString,
			String withString) {
		try {
			// String filePath =
			// Util.getResourcePath("set2/train_text/alt.atheism/49960");
			FileReader fileReader;
			fileReader = new FileReader(filePath);
			String string = IOUtils.toString(fileReader);
			fileReader.close();
			// String replaceString = "class";
			// String withString = "@class";
			string = string.replaceAll(replaceString, withString);
			File file = new File(filePath);
			Writer output = new FileWriter(file, false);
			IOUtils.write(string, output);
			output.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static boolean write(String filePath, String content, boolean append) {
		try {
			File file = new File(filePath);
			Writer output = new FileWriter(file, append);
			IOUtils.write(content, output);
			output.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static boolean createUserDir(String dirName) {
		try {
			File dir = new File(dirName);
			return !(!dir.exists() && !dir.mkdirs());
		} catch (Exception e) {
			return false;
		}
	}

	public static String getPercent(double i, double size) {
		float percent = (float) (i / size) * 100;
		return "" + percent + "%";
	}

	public static List<String> mesh(List<String> lines) {
		List<String> meshStrings = new ArrayList<String>();
		for (int i = 1; i < lines.size(); i++) {
			String string = lines.get(i);
			meshStrings.add(string.toLowerCase().replaceAll("[^a-z]", ""));
		}
		return meshStrings;
	}

	public static List<String> readInput(String fileName) {
		InputStream stream = Util.getInputStream(fileName);
		try {
			List<String> lines = IOUtils.readLines(stream);
			IOUtils.closeQuietly(stream);
			return lines;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
		}
		return null;
	}

	public static BigInteger factorial(long n) {
		BigInteger f = BigInteger.valueOf(1);
		for (long i = 1; i <= n; i++) {
			f = f.multiply(BigInteger.valueOf(i));
		}
		return f;
		// if (n > 1) {
		// return n * factorial(n - 1);
		// }
		// return 1;
	}

	private static long factorial(long n, long mod) {
		long f = 1;
		for (long i = 2; i <= n; i++) {
			f *= i;
			f %= mod;
		}
		return f;
	}

	public static long comb(long k, long n) {
		BigInteger a = Util.factorial(n);
		BigInteger b = Util.factorial(k);
		BigInteger c = Util.factorial(n - k);
		BigInteger res = a.divide(b).divide(c);
		return res.longValue();
	}

	public static long comb(long k, long n, long mod) {
		long a = Util.factorialSecv(Math.max(k, n - k), n, mod);
		long b = Util.factorial(Math.min(k, n - k), mod);
		// long a = Util.factorial(n, mod);
		// long b = Util.factorial(k, mod);
		// long c = Util.factorial(n - k, mod);
		// return a / b / c;
		// BigInteger a = BigInteger.valueOf(Util.factorial(n, mod));
		// BigInteger b = BigInteger.valueOf(Util.factorial(k, mod));
		// BigInteger c = BigInteger.valueOf(Util.factorial(n - k, mod));
		// BigInteger res = a.divide(b).divide(c);
		return a / b;

	}

	private static long factorialSecv(long k, long n, long mod) {
		long f = 1;
		for (long i = k; i <= n; i++) {
			f *= i;
			f %= mod;
		}
		return f;
	}
}
